[8.2-stable] Fix Attachment#deletable? false positives#3859
Merged
tvdeyen merged 4 commits into8.2-stablefrom Apr 28, 2026
Merged
[8.2-stable] Fix Attachment#deletable? false positives#3859tvdeyen merged 4 commits into8.2-stablefrom
tvdeyen merged 4 commits into8.2-stablefrom
Conversation
Extracts the shared polymorphic-reference subquery from RelatableResource into a constant so including classes can reuse it if they oeverride the .deletable scope, because you can't call super in scopes. (cherry picked from commit d33e09c)
The deletable scope only considered polymorphic related_object references, which missed attachments linked from /attachment/:id/download URLs written into ingredient values by the file tab of the link dialog. On sites where attachments are linked from Richtext, Link, or Html ingredients, every attachment was reported as deletable, risking accidental data loss. The scope now adds a correlated NOT EXISTS against ingredient value columns. The per-row LIKE pattern is built with Arel::Nodes::Concat so it compiles to || on SQLite and PostgreSQL and to CONCAT() on MySQL without adapter-specific SQL. The /download suffix in the pattern delimits the id, so matching attachment 1 does not incorrectly pull in URLs pointing at attachment 10. (cherry picked from commit 3ed90b4)
Rendering the attachment index used to call Attachment#deletable? per row to decide which delete buttons to enable. Each call issued up to two queries (the polymorphic related_ingredients check and the LIKE scan for ingredient-value references), so a page of N attachments cost up to 2N extra queries in addition to the main fetch. The controller now runs the deletable scope once for the ids on the current page and stores the result in a Set. Because the scope relation is chained as the subquery source of an IN clause, Rails applies the same Ransack filter, sort, and pagination on the database side without materializing the ids Ruby-side, keeping the check tight to the rows the view actually renders. (cherry picked from commit f425112)
Rendering the picture archive used to call Picture#deletable? per row to decide which delete buttons to show. Each call issued up to two queries (the polymorphic related_ingredients check and the LIKE scan for ingredient-value references), so a page of N pictures cost up to 2N extra queries in addition to the main fetch. The controller now runs the deletable scope once for the ids on the current page and stores the result in a Set. Because the scope relation is chained as the subquery source of an IN clause, Rails applies the same Ransack filter, sort, and pagination on the database side without materializing the ids Ruby-side, keeping the check tight to the rows the view actually renders. The same preload is wired to the update action since it re-renders the picture partial via turbo stream. (cherry picked from commit f32d773)
3 tasks
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## 8.2-stable #3859 +/- ##
===========================================
Coverage 98.06% 98.06%
===========================================
Files 322 322
Lines 8530 8547 +17
===========================================
+ Hits 8365 8382 +17
Misses 165 165 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
tvdeyen
approved these changes
Apr 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backport
This will backport the following commits from
mainto8.2-stable:Questions ?
Please refer to the Backport tool documentation